
/*
 * Copyright (c) 2015-2019 Cadence Design Systems, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "xtensa_rtos.h"
#include "portmacro.h"
#include "asm-offsets.h"

#include <xtensa/hal.h>

/*******************************************************************************

_xt_mpu_restore

    !! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !!

Restores task's MPU state

Entry Conditions:
    A0  = Return address in caller.

*******************************************************************************/
#if portUSING_MPU_WRAPPERS

    .altmacro

    .macro  mpu_set_entry  entry
    /*
     * Load both first and last entry for a range to avoid memory access
     * when region is partially modified which may result in a TLB multihit.
     */
    l32i    a3, a2, (TCB_MPU_SETTINGS_OFF + (MPU_ENTRY_SIZE * ((portNUM_MAX_SWAPPED_MPU_PAIRS - \entry) * 2 + 1)) + MPU_ENTRY_AT_OFF)
    l32i    a4, a2, (TCB_MPU_SETTINGS_OFF + (MPU_ENTRY_SIZE * ((portNUM_MAX_SWAPPED_MPU_PAIRS - \entry) * 2 + 1)) + MPU_ENTRY_AS_OFF)
    l32i    a5, a2, (TCB_MPU_SETTINGS_OFF + (MPU_ENTRY_SIZE * ((portNUM_MAX_SWAPPED_MPU_PAIRS - \entry) * 2 + 0)) + MPU_ENTRY_AT_OFF)
    l32i    a6, a2, (TCB_MPU_SETTINGS_OFF + (MPU_ENTRY_SIZE * ((portNUM_MAX_SWAPPED_MPU_PAIRS - \entry) * 2 + 0)) + MPU_ENTRY_AS_OFF)
    wptlb   a3, a4
    wptlb   a5, a6
    .endm

    .section "privileged_functions"
    .global _xt_mpu_restore
    .type   _xt_mpu_restore,@function
    .align  4
_xt_mpu_restore:

    movi    a3, g_num_used_mpu_entries
    l32i    a3, a3, 0
    movi    a4, .Lset

    /*
     * a3 = .Lset - 18 * g_num_used_mpu_entries -- is the address of code
     * that loads MPU entries of the first g_num_used_mpu_entries regions.
     * 18 is the size of piece of code generated by one mpu_set_entry macro
     */
    slli    a2, a3, 4
    addx2   a2, a3, a2
    sub     a3, a4, a2

    movi    a2, pxCurrentTCB
    l32i    a2, a2, 0

    jx      a3

    .begin no-transform

    /* Load MPU entries from last to first (not in MPU order,
     * in pxCurrentTCB->xMPUSettings order).
     */
    .set i, 1
    .rept portNUM_MAX_SWAPPED_MPU_PAIRS
    mpu_set_entry %i
    .set i, i+1
    .endr
.Lset:
    .end no-transform
    isync

    ret

#ifdef portALIGN_SECTIONS
    .section privileged_functions
    .align  XCHAL_MPU_ALIGN

    .section privileged_data
    .align  XCHAL_MPU_ALIGN

    .section freertos_system_calls
    .align  XCHAL_MPU_ALIGN

    .section .text
    .align  XCHAL_MPU_ALIGN

    .section .data
    .align  XCHAL_MPU_ALIGN

    .section .literal
    .align  XCHAL_MPU_ALIGN

    .section .bss
    .align  XCHAL_MPU_ALIGN

    .section .rodata
    .align  XCHAL_MPU_ALIGN

    .section private_region1
    .align  XCHAL_MPU_ALIGN
    .section private_region2
    .align  XCHAL_MPU_ALIGN
    .section private_region3
    .align  XCHAL_MPU_ALIGN
    .section private_stack
    .align  XCHAL_MPU_ALIGN
#endif

#endif // portUSING_MPU_WRAPPERS
